/* $Id$ */
/* vim: set filetype=verilog ts=8 sw=4 tw=132: */
/*****************************************************************************
 
              (c) Copyright 1987 - 2012,  VIA Technologies, Inc.       
                            ALL RIGHTS RESERVED                            
                                                                     
 This design and all of its related documentation constitutes valuable and
 confidential property of VIA Technologies, Inc.  No part of it may be
 reproduced in any form or by any means   used to make any transformation
 / adaptation / redistribution without the prior written permission from the
 copyright holders. 
 
------------------------------------------------------------------------------

  DESCRIPTION:

  FEATURES:

  TODO:

  AUTHORS:
     Shawn Fang
    
------------------------------------------------------------------------------
                             REVISION HISTORY
    $Log$

*****************************************************************************/
module decode(
	/*
	output [31:0] valA,
	output [31:0] valB,

	input  clock,
	input  reset,
	input  [3:0] icode,
	input  [3:0] ifun,
	input  [3:0] rA,
	input  [3:0] rB,
	input  [31:0] valE,
	input  [31:0] valM,
	input  cnd
    */
   // Outputs
		    output  [3:0] d_icode,//           (d_icode[3:0]),
                    output [3:0] d_ifun           ,// (d_ifun[3:0]),
                    output reg[2:0] d_stat           ,// 
                    output [31:0] d_valC            ,//(d_valC[31:0]),
                    output reg[31:0] d_valA            ,//(d_valA[31:0]),
                    output reg[31:0] d_valB            ,//(d_valB[31:0]),
                    output reg[3:0] d_dstE            ,//(d_dstE[3:0]),
                    output [3:0]d_dstM            ,//(d_dstM[3:0]),
		    output reg    [3:0] d_srcA,
		    output reg    [3:0] d_srcB,
                     // Inputs
                    input  clock             ,//(clock),
                    input  reset             ,//(reset),
                    input  [3:0] f_icode           ,//(f_icode[3:0]),
                    input [3:0] f_ifun            ,//(f_ifun[3:0]),
                    input [2:0] f_stat            ,
                    input [3:0]  f_rA              ,//(f_rA[3:0]),
                    input [3:0]  f_rB              ,//(f_rB[3:0]),
                    input [31:0]  f_valC            ,//(f_valC[31:0]),
                    input [31:0]  f_valP            ,//(f_valP[31:0]),
                    input   m_cnd             ,//(m_cnd));

		    input [3:0] e_dstE,
		    input [31:0] e_valE,
                    input [31:0]  m_valE,
                    input  [3:0] m_dstE, 
		    input [31:0]   m_valM,
                    input  [3:0] m_dstM,
                    input [31:0]  w_valE,
                    input  [3:0] w_dstE,
                    input [31:0]  w_valM,
                    input  [3:0] w_dstM,
                    input   D_stall,
                    input   D_bubble
   );
wire   [3:0] d_rA,d_rB;
wire   [31:0] d_valP;
wire   [31:0] d_rvalA,d_rvalB;
always @(d_icode or d_rA)
begin
    case(d_icode)
	`IRRMOVL:d_srcA<=d_rA;
	`IRMMOVL:d_srcA<=d_rA;
	`IOPL:d_srcA<=d_rA;
	`IPUSHL:d_srcA<=d_rA;
	
	`IPOPL:d_srcA<=`RESP;
	`IRET:d_srcA<=`RESP;
	default:d_srcA<= `RNUL;
    endcase
end
always @ (d_icode or d_rB)
begin
    case(d_icode)
	`IRMMOVL:d_srcB<=d_rB;
	`IMRMOVL:d_srcB<=d_rB;
	`IMRMOVL:d_srcB<=d_rB;
	`IOPL:d_srcB<=d_rB;
	
	`IPUSHL:d_srcB<=`RESP;
	`IPOPL:d_srcB<=`RESP;
	`ICALL:d_srcB<=`RESP;
	`IRET:d_srcB<=`RESP;
	default:d_srcB<=`RNUL;
    endcase
end

always @(d_icode or m_cnd or d_rB)
begin
    case(d_icode)
	`IRRMOVL:d_dstE<=d_rB;//dstE<=cnd?rB:`RNUL;
	`IIRMOVL:d_dstE<=d_rB;
	`IOPL:d_dstE<=d_rB;

	`IPUSHL:d_dstE<=`RESP;	
	`IPOPL:d_dstE<=`RESP;
	`ICALL:d_dstE<=`RESP;
	`IRET:d_dstE<=`RESP;
	default:d_dstE<= `RNUL;
    endcase
end
assign d_dstM=(d_icode==`IMRMOVL||d_icode==`IPOPL)?d_rA:`RNUL;

//sel+fwd A
always @ (d_srcA or d_icode or e_valE or e_dstE or m_dstM or m_dstE or m_valE or m_valM or w_dstE or w_dstM or w_valM or w_valE or d_rvalA)
begin
    if(d_icode==`ICALL || d_icode==`IJXX)
	d_valA<=d_valP;
    else if(d_srcA==e_dstE)
	d_valA<=e_valE;
    else if(d_srcA==m_dstM)
	d_valA<=m_valM;
    else if(d_srcA==m_dstE)
	d_valA<=m_valE;
    else if(d_srcA==w_dstM)
	d_valA<=w_valM;
    else if(d_srcA==w_dstE)
	d_valA<=w_valE;
    else
	d_valA<=d_rvalA;	
end
//fwd B
always @ (d_srcB or e_dstE or e_valE
or m_dstM or m_valM
or m_dstE or m_valE 
or w_dstM or w_valM
or w_dstE or w_valE
or d_rvalB)
begin
    if(d_srcB==e_dstE)
	d_valB<=e_valE;
    else if(d_srcB==m_dstM)
	d_valB<=m_valM;
    else if(d_srcB==m_dstE)
	d_valB<=m_valE;
    else if(d_srcB==w_dstM)
	d_valB<=w_valM;
    else if(d_srcB==w_dstE)
	d_valB<=w_valE;
    else
	d_valB<=d_rvalB;

end

always @ (posedge clock or posedge reset)
    begin
	if(reset)
	    d_stat<=`SAOK;
	else
	begin
	    if(D_stall)
		d_stat<=d_stat;
	    else if(D_bubble)
		d_stat<=`SAOK;
	    else
		d_stat<=f_stat;
	end
    end

 ppregs_D U_ppregs_D
    (
	.clock(clock),
	.reset(reset),
	.D_stall(D_stall),
        .D_bubble(D_bubble),
	.icode_i(f_icode),
	.ifun_i(f_ifun),
	.rA_i(f_rA),
	.rB_i(f_rB),
	.valC_i(f_valC),
	.valP_i(f_valP),
	
	.icode_o(d_icode),
	.ifun_o(d_ifun),
	.rA_o(d_rA),
	.rB_o(d_rB),
	.valC_o(d_valC),
	.valP_o(d_valP)
    );
regFile U_regFile(
    //outputs
    .d_rvalA(d_rvalA),//[31:0]
    .d_rvalB(d_rvalB),//[31:0]
    //inputs
    .clock(clock),
    .reset(reset),
    .d_srcA(d_srcA),//[3:0]
    .d_srcB(d_srcB),//[3:0]
    .w_dstE(w_dstE),//[3:0]
    .w_dstM(w_dstM),//[3:0]
    .w_valE(w_valE),//[31:0]
    .w_valM(w_valM));//[31:0]
endmodule
